home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
ab20
/
unarced
/
datacomm
/
vltjr
/
rexx
/
fifobbs.rexx
< prev
next >
Wrap
OS/2 REXX Batch file
|
1995-03-17
|
31KB
|
1,222 lines
/** FifoBBS.rexx
*
* Test of fifo-handler. A small BBS. Really small...
*
* This requires VLT or VLTjr version 5.028 or later, and
* Matt Dillon's Fifo.library and fifo-handler. Please
* install these files and mount fifo: before running this.
*
* Usage: FifoBBS [local | remote]
*
* FifoBBS, when invoked without arguments will run a fake BBS
* in the current CLI. When invoked with the "local" argument,
* it will run with a local VLT, bypassing the serial port.
* In neither of these cases will "UPLOAD" or "DOWNLOAD" work.
* When invoked with the "remote" argument, it will run as a
* real BBS, through the serial port.
*
* The BBS installs itself almost completely. All you have to
* do is assign FifoBBS: or change the BBSdevice string later on
* to the location you want. You will also need to set up VLT
* for running with its pipes on. After starting the BBS for
* for the first time, you can log on as Sysop, password
* SYSOP. It will ask you to change your password. From that
* moment on, you're in business. People can register, the
* sysop can validate them. Once on the system, type help to
* find a list of commands.
*
* Alpha 0.4 by W.G.J. Langeveld, 30 January 1991.
*
**/
parse arg action
/*
* Allow no interruptions for secure operation
*/
SIGNAL ON BREAK_C
SIGNAL ON BREAK_D
SIGNAL ON BREAK_E
SIGNAL ON BREAK_F
SIGNAL ON ERROR
SIGNAL ON FAILURE
SIGNAL ON HALT
SIGNAL ON SYNTAX
/*
* This one is really for debugging purposes:
*/
SIGNAL ON NOVALUE
Options failat 300
SignalLabel = "Start"
/*
* Trick: here are all the global variables we want accessible to all
* routines. Watch the way interpret is used in the Procedure definitions
*/
GLOBAL = "GLOBAL SignalLabel BBSdevice BBSusers BBSlistings"
GLOBAL = GLOBAL || " BBSgeneral BBSmail BBSadmin BBSsysmsg BBSprompt"
GLOBAL = GLOBAL || " Protocols. CurrentUser."
/*
* Get the support library.
*/
check = addlib('rexxsupport.library', 0, -30, 0)
/*
* BBS definitions
*/
BBSdevice = "FifoBBS:"
BBSusers = BBSdevice"users"
BBSlistings = BBSdevice"listings"
BBSgeneral = BBSdevice"general"
BBSmail = BBSdevice"mail"
BBSadmin = BBSdevice"admin"
BBSsysmsg = BBSdevice"admin/system.msg"
BBSprompt = "FifoBBS> "
/*
* Check if the sections exist, or else make them
*/
if ~exists(BBSdevice) then do
say "You must set up an assignment called "BBSdevice
exit 0
end
if ~exists(BBSusers) then call Makedir(BBSusers)
if ~exists(BBSlistings) then call Makedir(BBSlistings)
if ~exists(BBSgeneral) then call Makedir(BBSgeneral)
if ~exists(BBSmail) then call Makedir(BBSmail)
if ~exists(BBSadmin) then call Makedir(BBSadmin)
if ~exists(BBSsysmsg) then address command "echo >"BBSsysmsg' "No news"'
/*
* If there's no sysop account, make one
*/
if ~exists(BBSmail"/Sysop") then do
Tmp. = ""
Tmp.Account = "Sysop"
Tmp.Password = "SYSOP"
Tmp.Access = 5
Tmp.Name = "Sysop"
Tmp.MsgCount = 0
Tmp.MailCount = 0
Tmp.Protocol = 1
call SetRecord()
call Makedir(BBSmail"/Sysop")
end
/*
* Transfer Protocols
*/
Protocols.0 = 5
Protocols.1.nam = "XMODEM"
Protocols.1.lib = "xprxmodem.library"
Protocols.1.set = "C1,K1"
Protocols.2.nam = "ZMODEM"
Protocols.2.lib = "xprzmodem.library"
Protocols.2.set = "T?,OS,B1,AN,DN,KN,SN,RN"
Protocols.3.nam = "Kermit"
Protocols.3.lib = "xprkermit.library"
Protocols.3.set = "OCY,GN,TN,P1500,B3"
Protocols.4.nam = "CIS QuickB"
Protocols.4.lib = "xprquickb.library"
Protocols.4.set = "TC,OS,B1,AN,DN,KN"
Protocols.5.nam = "ASCII"
Protocols.5.lib = "xprascii.library"
Protocols.5.set = "50"
/*
* Redirect I/O to VLT's pipes
* For use as a BBS, use VLTR (remote). For local tests
* use VLTL (local).
*/
if action = "remote" then pip = "VLTR"
else pip = "VLTL"
/*
* When action is not either "local" or "remote", you will run in
* the CLI (and you will see some echoes not otherwise present).
*/
if action ~= "" then do
call close("STDIN")
call close("STDOUT")
/*
* First open fifo for read/write and assign to stdin
*/
if ~open("STDIN", "fifo:"pip"/rws") then do
say "Can't open read pipe"
exit 0
end
/*
* Identify stdin with the "current console"
*/
call pragma('*', "STDIN")
/*
* Open stdout to the current console for write.
*/
if ~open("STDOUT", '*', "W") then do
say "Can't open write pipe"
exit 0
end
end
/*
* Wait for <cr>. Here's where we go on severe problems.
*/
Start:
s = GetCommand("", 0)
/*
* Welcome message.
*/
say "+--------------------------------------------------+"
say "| FifoBBS - Only authorized users are welcome! +"
say "+--------------------------------------------------+"
/*
* Log in. Don't let users without sufficient privilege get past here.
*/
CurrentUser. = ""
call Login()
if CurrentUser.Access < 3 then interpret "SIGNAL" SignalLabel
/*
* If user is Sysop, make sure the password is changed first time
*/
if upper(CurrentUser.Account) = "SYSOP" then do
do while upper(CurrentUser.Password) = "SYSOP"
say "You MUST change the Sysop password now!"
call ChangePassword()
end
end
/*
* System message
*/
if exists(BBSsysmsg) then address command "type "BBSsysmsg
/*
* Unread mail
*/
n = GetMsgLeft(BBSmail"/"CurrentUser.Account, CurrentUser.MailCount)
if n ~= 0 then say "You have "n" unread mail message"Esses(n)
/*
* Unread regular messages
*/
n = GetMsgLeft(BBSgeneral, CurrentUser.MsgCount)
if n ~= 0 then say "You have "n" unread general message"Esses(n)
/*
* Main loop. Not too many commands yet. But you get the
* idea... Some commands are only available with level 5 clearance.
*/
do i = 1
s = GetCommand(BBSprompt, 1)
parse var s cmd arg1 arg2 .
cmd = upper(cmd)
select
when abbrev("DOWNLOAD", cmd, 2) then call Download(arg1)
when abbrev("ENTER", cmd, 3) then call EnterMsg("")
when abbrev("EXIT", cmd, 4) then call ExitBBS(cmd)
when abbrev("HELP", cmd, 1) then call HelpList("")
when abbrev("LIST", cmd, 2) then call ListFiles()
when abbrev("LOGOFF", cmd, 2) then leave i
when abbrev("MAIL", cmd, 2) then call DoMail()
when abbrev("PASSWORD", cmd, 3) then call ChangePassword()
when abbrev("PROTOCOL", cmd, 3) then call ChangeProtocol(arg1)
when abbrev("REGISTER", cmd, 3) then call Register(cmd)
when abbrev("READ", cmd, 2) then call ReadMsg(arg1)
when abbrev("SHOW", cmd, 2) then call ShowRecord(arg1)
when abbrev("SYSTEM", cmd, 2) then call DoSystem(cmd)
when abbrev("UPLOAD", cmd, 2) then call UpLoad(arg1)
when abbrev("USERS", cmd, 2) then call ShowUsers()
when abbrev("VALIDATE", cmd, 1) then call Validate(cmd, arg1, arg2)
otherwise call HelpList(cmd)
end
end
/*
* Save message and mail count
*/
n = CurrentUser.MsgCount
m = CurrentUser.MailCount
Tmp.Account = CurrentUser.Account
call GetRecord()
Tmp.MsgCount = n
Tmp.MailCount = m
call SetRecord()
/*
* Logout
*/
say CurrentUser.Name" logged off at "time()
interpret "SIGNAL" SignalLabel
/**************************************************************/
/**************** Functions ***********************************/
/**************************************************************/
/**
*
* Change the password
*
**/
ChangePassword: interpret "Procedure Expose" GLOBAL
Tmp.Account = CurrentUser.Account
if GetRecord() = 1 then do
t = upper(GetCommand("Old Password: ", 0))
if t ~= Tmp.Password then do
say "Invalid Password"
return
end
t = upper(GetCommand("New Password: ", 0))
u = upper(GetCommand("Verification: ", 0))
if u ~= t then do
say "Verification doesn't match new password, aborted"
return
end
else do
Tmp.Password = u
CurrentUser.Password = u
call SetRecord()
end
end
return
/**
*
* Change the transfer protocol
*
**/
ChangeProtocol: interpret "Procedure Expose" GLOBAL
arg s
if s = "" then do
say "Transfer Protocol:"
do i = 1 to Protocols.0
say i". "Protocols.i.nam
end
i = CurrentUser.Protocol + 0
say "Your current protocol is "Protocols.i.nam
end
Tmp.Account = CurrentUser.Account
if GetRecord() = 1 then do
do i = 1
if s = "" then t = upper(GetCommand("Enter new protocol (1 - 5): ", 1))
else t = s
if (t ~= 1) & (t ~= 2) & (t ~= 3) & (t ~= 4) & (t ~= 5) then do
say "A number from 1 through 5 was expected"
s = ""
iterate i
end
leave i
end
CurrentUser.Protocol = t
if s = "" then do
if GetYesNo("Save for next time? ") = 1 then do
Tmp.Protocol = t
call SetRecord()
end
end
end
return
/**
*
* Collect a message
*
**/
CollectMsg: interpret "Procedure Expose" GLOBAL "msg."
arg comm
say "Enter the message below."
say "Enter a dot as the first character on a line to exit."
if comm = "" then do
msg.3 = "Title: " || GetCommand("Title: ", 1)
ni = 4
end
else ni = 3
do k = 1
do n = ni
msg.n = GetCommand(">", 1)
if substr(msg.n, 1, 1) = "." then leave n
end
do i = 1
s = upper(GetCommand("Quit, Continue, List, Post: ", 1))
if abbrev("QUIT", s, 1) then return 0
else if abbrev("LIST", s, 1) then do
do j = 3 to n - 1
say msg.j
end
end
else if abbrev("POST", s, 1) then leave k
else if abbrev("CONTINUE", s, 1) then do
ni = n
leave i
end
end
end
return n - 1
/**
*
* Copy the user's record from Tmp.
*
**/
CopyRecord: interpret "Procedure Expose" GLOBAL "Tmp."
CurrentUser.Account = Tmp.Account
CurrentUser.Password = Tmp.Password
CurrentUser.Access = Tmp.Access
CurrentUser.Name = Tmp.Name
CurrentUser.City = Tmp.City
CurrentUser.Country = Tmp.Country
CurrentUser.Telephone = Tmp.Telephone
CurrentUser.MsgCount = Tmp.MsgCount
CurrentUser.MailCount = Tmp.MailCount
CurrentUser.Protocol = Tmp.Protocol
return
/**
*
* Mail subsystem. Two commands: read and enter. They use the same
* basic functions as the main system, but with different paths.
*
**/
DoMail: interpret "Procedure Expose" GLOBAL
do i = 1
s = upper(GetCommand("Mail: ", 1))
parse var s cmd arg1 .
select
when abbrev("TO", cmd, 2) then call EnterMail("", arg1)
when abbrev("HELP", cmd, 1) then call HelpLMail("")
when abbrev("QUIT", cmd, 1) then leave i
when abbrev("READ", cmd, 2) then call ReadMail(arg1)
when abbrev("SHOW", cmd, 2) then call ShowRecord(arg1)
when abbrev("USERS", cmd, 2) then call ShowUsers()
otherwise call HelpLMail(cmd)
end
end
return
/**
*
* Download an existing file
*
**/
DownLoad : interpret "Procedure Expose" GLOBAL
parse arg filnam
if filnam = "" then filnam = GetCommand("File name? ", 1)
if ~exists(BBSlistings"/"filnam) then do
say "Can't find file "filnam
return
end
say "Get ready to receive file "filnam
proto = CurrentUser.Protocol + 0
address VLT "transfer protocol external; transfer mode image"
address VLT "xpr select "Protocols.proto.lib
address VLT "CD "BBSlistings
if Protocols.proto.set ~= "" then address VLT "xpr init "Protocols.proto.set
address VLT "file send "BBSlistings"/"filnam
/*
* Switch back to XMODEM protocol so that we can't automatically start
* receiving stuff.
*/
address VLT "transfer protocol XMODEM"
return
/**
*
* More or less direct access to the system
*
**/
DoSystem: interpret "Procedure Expose" GLOBAL
parse arg s
if CurrentUser.Access < 5 then do
call HelpList(s)
return
end
/*
* In case a command breaks, this is the label we want to get
* back to.
*/
SysCall: SignalLabel = "SysCall"
do i = 1
s = GetCommand("$ ", 1)
parse var s cmd rest
cmd = upper(cmd)
if abbrev("RETURN", cmd, 3) then do
leave i
end
else if (cmd = "CD") & (rest ~= "") then do
call pragma("Directory", strip(rest))
end
else do
address command s
end
end
/*
* Change the label back to what it was.
*/
SignalLabel = "Start"
return
/**
*
* Enter a new mail message.
*
**/
EnterMail: interpret "Procedure Expose" GLOBAL
parse arg comm, dest
if dest = "" then dest = GetCommand("To: ", 1)
Tmp.Account = dest
if GetRecord() ~= 1 then do
say "No such account"
return
end
n = CollectMsg(comm)
if n = 0 then return
call MakeFile(comm, BBSmail"/"CurrentUser.Account, n)
if Tmp.Account ~= CurrentUser.Account then do
call MakeFile(comm, BBSmail"/"Tmp.Account, n)
end
return
/**
*
* Enter a new message. Someone should build in an editor...
*
**/
EnterMsg : interpret "Procedure Expose" GLOBAL
parse arg comm
n = CollectMsg(comm)
if n = 0 then return
call MakeFile(comm, BBSgeneral, n)
return
/**
*
* An s or not an s
*
**/
Esses: interpret "Procedure Expose" GLOBAL
arg n
if n > 1 then return "s"
return ""
/**
*
* Exit the BBS program
*
**/
ExitBBS: interpret "Procedure Expose" GLOBAL
parse arg s
if CurrentUser.Access >= 5 then exit 0
else call HelpList(s)
return
/**
*
* This gets the command from stdin. We can't use "pull"
* because it doesn't echo the way we open things (Fifo doesn't
* have a console handler) so we have to do it all ourselves (including
* echo and backspace). No command line editing yet.
* The first argument is the prompt string, the second argument
* specifies whether or not to echo what the user types.
* This routine checks for the presence of a "NO CARRIER"
* string at the end of the command line. If it is present, the
* session is aborted immediately. For this to work, you must make sure
* your modem detects carrier loss and sends this string.
*
**/
GetCommand: interpret "Procedure Expose" GLOBAL
parse arg pr, echo
/*
* Some constants
*/
cr = '0d'x
lf = '0a'x
bs = '08'x
crlf = cr||lf
call writech("STDOUT", pr)
command = ""
do forever
/*
* Read a character from STDIN
*/
s = readch("STDIN", 1)
/*
* If we get an EOF condition, abort this session.
*/
if eof("STDIN") then SIGNAL "Start"
/*
* Echo the character. Watch out for backspaces.
*/
if echo = 1 then do
if s ~= bs then call writech("STDOUT", s)
else if length(command) > 0 then call writech("STDOUT", bs" "bs)
end
/*
* We have a <cr> of <lf>. This is the end of a command line.
* Echo a line feed to STDOUT. Check if the line ends in
* NO CARRIER. If so, abort the session. Else, return the command.
*/
if s = cr | s = lf then do
call writech("STDOUT", lf)
nc = index(command, "NO CARRIER")
if nc ~= 0 then do
if nc = length(command) - 9 then do
say "NO CARRIER detected, aborting session"
SIGNAL "Start"
end
end
return command
end
/*
* It's a backspace. Take off the last character of the command.
*/
else if s = bs then do
l = length(command)
if l > 0 then command = substr(command, 1, l - 1)
end
/*
* A regular character. Add it to the command
*/
else command = command || s
end
return
/**
*
* Get highest numbered message in the source directory
*
**/
GetHighMsg: interpret "Procedure Expose" GLOBAL
parse arg source
files = showdir(source, "FILES")
/*
* Loop over the files, and get the highest unread message number
*/
high = 0
do i = 1
parse var files "msg."k files
if k > high then high = k
if files = "" then leave
end
return high
/**
*
* Get number of messages left to read.
*
**/
GetMsgLeft: interpret "Procedure Expose" GLOBAL
parse arg source, last
files = showdir(source, "FILES")
/*
* Loop over the files, and extract number of messages left to read (n)
*/
n = 0
do i = 1
parse var files "msg."k files
if k > last then n = n + 1
if files = "" then leave
end
return n
/**
*
* Retrieve a user's record
*
**/
GetRecord: interpret "Procedure Expose" GLOBAL "Tmp."
succ = 0
if open("fi", BBSusers"/"Tmp.Account) then do
t = readln("fi")
if t ~= "" then do
parse var t Tmp.Password '|' Tmp.Access '|' ,
Tmp.Name '|' Tmp.Address '|' ,
Tmp.City '|' Tmp.Country '|' ,
Tmp.Telephone '|' Tmp.MsgCount '|' ,
Tmp.MailCount '|' Tmp.Protocol '|'
succ = 1
end
call close("fi")
end
return succ
/**
*
* This gets a yes/no decision from stdin
* The single argument is used as the prompt.
*
**/
GetYesNo: interpret "Procedure Expose" GLOBAL
parse arg prompt
do i = 1
ss = upper(GetCommand(prompt" [Yes/No]: ", 1))
if substr(ss, 1, 1) = 'Y' then return 1
else if substr(ss, 1, 1) = 'N' then return 0
else do
say "A Yes or No was expected, retry"
end
end
return
/**
*
* List supported commands. Can be as extensive as you want.
*
**/
HelpList: interpret "Procedure Expose" GLOBAL
parse arg s
if s ~= "" then say "Unknown command: "s
Say "Supported commands are: "
Say "-------------------------+-------------------------------------"
Say "DOWNLOAD [filename] | Download a file [called filename]"
Say "ENTER | Enter a message"
if CurrentUser.Access >= 5 then
Say "*EXIT | Exit the BBS program"
Say "HELP | Display this list"
Say "LIST | List downloadable files"
Say "LOGOFF | Logoff"
Say "MAIL | Go to mail subsytem"
Say "PASSWORD | Set new password"
Say "PROTOCOL [n] | Set new transfer protocol [to n]"
Say "READ [message] | Read messages [starting at message]"
if CurrentUser.Access >= 5 then
Say "*REGISTER | Add a new user to the system"
Say "SHOW [name] | Show current record [of user ""name""]"
if CurrentUser.Access >= 5 then
Say "*SYSTEM | Change to system command level"
Say "UPLOAD [filename] | Upload a file [called filename]"
Say "USERS | Show the user list"
if CurrentUser.Access >= 5 then
Say "*VALIDATE [user] [level] | Validate a new user"
Say "-------------------------+-------------------------------------"
return
/**
*
* List supported commands in mail.
*
**/
HelpLMail: interpret "Procedure Expose" GLOBAL
parse arg s
if s ~= "" then say "Unknown command: "s
Say "Supported commands while in mail are: "
Say "----------------+-------------------------------------"
Say "TO | Enter a message"
Say "HELP | Display this list"
Say "QUIT | Quit from the mail subsystem"
Say "READ [message] | Read messages [starting at message]"
Say "SHOW [name] | Show current record [of user ""name""]"
Say "USERS | Show the user list"
Say "----------------+-------------------------------------"
return
/**
*
* List downloadable files
*
**/
ListFiles: interpret "Procedure Expose" GLOBAL
address command "list "BBSlistings" nohead"
return
/**
*
* Handle logins and new registrations.
* Argument is a user account name, so we can log ourselves back in
* if we as a sysop have added someone else using Register().
*
**/
Login: interpret "Procedure Expose" GLOBAL
Tmp. = ""
Tmp.Access = 0
CurrentUser.Access = 0
Tmp.Account = upper(GetCommand("Username: ", 1))
if Tmp.Account = "NEW" then do
call Register("")
return
end
else if GetRecord() = 0 then do
say "Not registered."
say "To register, use the NEW account."
end
else do
s = upper(GetCommand("Password: ", 0))
if s ~= Tmp.Password then do
say "Unauthorized."
say "Bye now..."
Tmp.Access = 0
end
end
call CopyRecord()
if CurrentUser.Access = 2 then say "You are not yet validated"
return
/**
*
* Make a file header, and add it in the destination directory
*
**/
MakeFile: interpret "Procedure Expose" GLOBAL "msg."
parse arg comm, dest, nlins
/*
* Get list of files.
*/
files = showdir(dest, "FILES")
/*
* Loop over the files, extract the highest message number and add
* 1 for the current message.
*/
high = 0
do i = 1
parse var files "msg."k files
if k > high then high = k
if files = "" then leave
end
high = high + 1
/*
* Header
*/
msg.0 = "=========="
msg.1 = "# "high", "date()", "time()", from "CurrentUser.Account". "
if comm ~= "" then msg.1 = msg.1 || "Comment to "comm"."
msg.2 = "----------"
if ~open("fo", dest"/msg."high, "W") then do
say "Cannot add a message right now"
return
end
do i = 0 to nlins
call writeln("fo", msg.i)
end
call close("fo")
return
/**
*
* Read mail messages.
* One argument: the message number to start reading. This resets the
* message pointer. This also allows you to skip to the last.
*
**/
ReadMail: interpret "Procedure Expose" GLOBAL
parse arg nm
/*
* If we have a message number for argument set user's message pointer
* to just before that.
*/
if nm ~= "" then CurrentUser.MailCount = nm - 1
/*
* Unread mail
*/
source = BBSmail"/"CurrentUser.Account
n = GetMsgLeft(source, CurrentUser.MailCount)
if n ~= 0 then say "You have "n" unread mail message"Esses(n)
else CurrentUser.MailCount = GetHighMsg(source)
/*
* Message read loop
*/
do i = 1 to n
do k = CurrentUser.MailCount + 1
if ~exists(source"/msg."k) then iterate k
address command "type "source"/msg."k
CurrentUser.MailCount = k
do j = 1
s = upper(GetCommand("[Quit, Again, Delete, Reply, Next = <cr>]: ", 1))
if abbrev("QUIT", s, 1) then return
else if abbrev("AGAIN", s, 1) then do
CurrentUser.MailCount = k - 1
i = i - 1
end
else if abbrev("DELETE", s, 1) then do
call Delete(source"/msg."k)
say "Deleted"
CurrentUser.MailCount = k - 1
end
else if abbrev("REPLY", s, 1) then do
if open("fi", source"/msg."k) then do
call readln("fi")
t = readln("fi")
parse var t dummy "from " owner ". " rest
call close("fi")
call EnterMail(k, owner)
end
end
else if abbrev("NEXT", s, 1) then nop
else if s = "" then nop
else iterate j
iterate i
end
end
end
say "No more unread messages"
return
/**
*
* Read messages.
* Two arguments: (1) the message number to start reading. This resets the
* message pointer. This also allows you to skip to the last. (2) The
* source directory to read from.
*
**/
ReadMsg : interpret "Procedure Expose" GLOBAL
parse arg nm
/*
* If we have a message number for argument set user's message pointer
* to just before that.
*/
if nm ~= "" then CurrentUser.MsgCount = nm - 1
/*
* Unread regular messages
*/
source = BBSgeneral
n = GetMsgLeft(source, CurrentUser.MsgCount)
if n ~= 0 then say "You have "n" unread general message"Esses(n)
else CurrentUser.MsgCount = GetHighMsg(source)
/*
* Message read loop
*/
do i = 1 to n
do k = CurrentUser.MsgCount + 1
if ~exists(source"/msg."k) then iterate k
address command "type "source"/msg."k
CurrentUser.MsgCount = k
do j = 1
s = upper(GetCommand("[Quit, Again, Delete, Comment, Next = <cr>]: ", 1))
if abbrev("QUIT", s, 1) then return
else if abbrev("AGAIN", s, 1) then do
CurrentUser.MsgCount = k - 1
i = i - 1
end
else if abbrev("DELETE", s, 1) then do
if open("fi", source"/msg."k) then do
call readln("fi")
t = readln("fi")
parse var t dummy "from " owner ". " rest
call close("fi")
if owner = CurrentUser.Account then do
call Delete(source"/msg."k)
say "Deleted"
end
else do
say "You didn't write this message"
if CurrentUser.Access >= 5 then do
if GetYesNo("Withdraw anyway? ") = 1 then do
call Delete(source"/msg."k)
say "Deleted"
end
end
end
end
end
else if abbrev("COMMENT", s, 1) then call EnterMsg(k, source)
else if abbrev("NEXT", s, 1) then nop
else if s = "" then nop
else iterate j
iterate i
end
end
end
say "No more unread messages"
return
/**
*
* Register a new user. The new user is immediately added to the
* system, but his access code is 2 which doesn't allow her to
* log in yet. The Sysop uses the Validate command to set the access
* code to a higher level. 3 is suggested... 5 gives system privileges.
*
**/
Register: interpret "Procedure Expose" GLOBAL
parse arg s
/*
* If access = 0 this is a new user. If access = 5, this is called by
* the Sysop.
*/
if CurrentUser.Access = 0 then prefix = "Your "
else if CurrentUser.Access < 5 then do
call HelpList(s)
return
end
else prefix = "New "
/*
* Generate registration record
*/
Tmp.Account = GetCommand(prefix"account name: ", 1)
if GetRecord() = 1 then do
say "Account name already taken"
return
end
Tmp.Password = upper(GetCommand(prefix"password: ", 0))
Tmp.Name = GetCommand(prefix"full name: ", 1)
Tmp.Address = GetCommand(prefix"address: ", 1)
Tmp.City = GetCommand(prefix"city, zip: ", 1)
Tmp.Country = GetCommand(prefix"country and/or state: ", 1)
Tmp.Telephone = GetCommand(prefix"telephone number: ", 1)
Tmp.Protocol = 1
Tmp.Access = 2
Tmp.MsgCount = 0
Tmp.MailCount = 0
say "You are:"
say Tmp.Name
say Tmp.Address
say Tmp.City
say Tmp.Country
say Tmp.Telephone
if GetYesNo("Correct? ") = 1 then do
call SetRecord()
if CurrentUser.Access = 0 then do
say "Please give the Sysop a chance to validate you (usually < 24 hours)."
say "Thank you for registering with this BBS."
end
end
return
/**
*
* Change a user's record
*
**/
SetRecord: interpret "Procedure Expose" GLOBAL "Tmp."
if Tmp.Access ~= 0 then do
t = Tmp.Password || '|' || Tmp.Access || '|' ||,
Tmp.Name || '|' || Tmp.Address || '|' ||,
Tmp.City || '|' || Tmp.Country || '|' ||,
Tmp.Telephone || '|' || Tmp.MsgCount || '|' ||,
Tmp.MailCount || '|' || Tmp.Protocol || '|'
if open("fo", BBSusers"/"Tmp.Account, "W") then do
call writeln("fo", t)
call close("fo")
end
end
else call Delete(BBSusers'/'Tmp.Account)
return
/**
*
* Show a user's stats.
*
**/
ShowRecord: interpret "Procedure Expose" GLOBAL
arg username
if username = "" then Tmp.Account = CurrentUser.Account
else Tmp.Account = username
if GetRecord() = 1 then do
say "Account info for "Tmp.Account":"
say Tmp.Name
say Tmp.Address
say Tmp.City
say Tmp.Country
say Tmp.Telephone
/*
* If asking about another user, don't need to show protocol.
* If asking about ourselves, then show current protocol, not "saved" one.
*/
if username = "" then do
i = CurrentUser.Protocol + 0
say "Transfer protocol: "Protocols.i.nam
end
end
else say "User "username" not found"
return
/**
*
* List files
*
**/
ShowUsers: interpret "Procedure Expose" GLOBAL
address command "list "BBSusers" nohead quick"
return
/**
*
* Upload a new file
*
**/
UpLoad : interpret "Procedure Expose" GLOBAL
parse arg filnam
if filnam = "" then filnam = GetCommand("File name? ", 1)
if exists(BBSlistings"/"filnam) then do
say filnam" already exists!"
return
end
say "Now send file "filnam
proto = CurrentUser.Protocol + 0
address VLT "transfer protocol external; transfer mode image"
address VLT "xpr select "Protocols.proto.lib
address VLT "CD "BBSlistings
if Protocols.proto.set ~= "" then address VLT "xpr init "Protocols.proto.set
address VLT "file receive "BBSlistings"/"filnam
/*
* Switch back to XMODEM protocol so that we can't automatically start
* receiving stuff.
*/
address VLT "transfer protocol XMODEM"
return
/**
*
* Routine to validate FifoBBS users. Only callable by the Sysop.
*
**/
Validate: interpret "Procedure Expose" GLOBAL
parse arg s, nam, acc .
if CurrentUser.Access < 5 then do
call HelpList(s)
return
end
if nam = "" then Tmp.Account = GetCommand("Name: ", 1)
else Tmp.Account = nam
if GetRecord() = 0 then do
say "Unknown account"
return
end
if ~exists(BBSmail"/"Tmp.Account) then call Makedir(BBSmail"/"Tmp.Account)
if acc = "" then do
say "Account info for "Tmp.Account":"
say Tmp.Name
say Tmp.Address
say Tmp.City
say Tmp.Country
say Tmp.Telephone
say "Transfer protocol: "Tmp.Protocol
say "Access code: "Tmp.Access
if GetYesNo("Change access code? ") = 1 then do
Tmp.Access = GetCommand("Enter new access code: ", 1)
call SetRecord()
end
end
else do
Tmp.Access = acc
call SetRecord()
end
return
BREAK_C:
BREAK_D:
BREAK_E:
BREAK_F:
ERROR:
FAILURE:
HALT:
IOERROR:
NOVALUE:
SYNTAX:
say "Command returned with error"
interpret "SIGNAL" SignalLabel
exit 0